(**************************************************************************)
(*  Copyright (c) 2007, Sebastien MONDET                                  *)
(*                                                                        *)
(*  Permission is hereby granted, free of charge, to any person           *)
(*  obtaining a copy of this software and associated documentation        *)
(*  files (the "Software"), to deal in the Software without               *)
(*  restriction, including without limitation the rights to use,          *)
(*  copy, modify, merge, publish, distribute, sublicense, and/or sell     *)
(*  copies of the Software, and to permit persons to whom the             *)
(*  Software is furnished to do so, subject to the following              *)
(*  conditions:                                                           *)
(*                                                                        *)
(*  The above copyright notice and this permission notice shall be        *)
(*  included in all copies or substantial portions of the Software.       *)
(*                                                                        *)
(*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *)
(*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES       *)
(*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND              *)
(*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT           *)
(*  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,          *)
(*  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING          *)
(*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR         *)
(*  OTHER DEALINGS IN THE SOFTWARE.                                       *)
(**************************************************************************)


(** The "main" (with some testing and portability code) *)

(******************************************************************************)
(** {3 Test functions} *)

(** MIDI file parsing *)
let test_parse_and_print_midi_file file = (
  try (
    let midi_data = MidiFile.parse_smf file in
    (*
      let the_other_file = "copy_of_" ^ file in
      MidiFile.write_smf midi_data the_other_file ;
      let midi_data = MidiFile.parse_smf the_other_file in
    *)
    Printf.printf "File %s\n" file;
    Printf.printf "%s" (Midi.midi_to_string midi_data) ;
  ) with
  | Sys_error msg -> Log.warn "Parse Midi File got SYS error: %s\n" msg;
  | exc -> 
      Log.warn "Parse Midi File got an exception: %s\n"
      (Printexc.to_string exc);
)

(******************************************************************************)
(** {3 Inspection functions} *)

(**/**)
let used_channel = ref stdout
let pr (form:('a, out_channel, unit ) format) = (
  Printf.fprintf !used_channel ( form ^^ "%!" )
)
(**/**)

let str_of_cmd cmd = (

  let uname_in = Unix.open_process_in cmd in
  let buf = Buffer.create 128 in
  let _ = try (
    while true do
      Buffer.add_char buf (input_char uname_in);
    done
  ) with End_of_file -> () in
  let _ = Unix.close_process_in uname_in in
  Buffer.contents buf 
)
let print_cmd cmd = (
  pr "```\nocaml@home:/bin/sh$ %s\n%s```\n" cmd (str_of_cmd cmd);
)


let make_inspection file = (
  let module Names = StringServer.App in

  let f = open_out file in
  used_channel := f ;

  pr "%s's Portability Inspection Report\n" !Names.app_name;
  pr "Generated by %s %s\n" !Names.app_name !Names.version;
  pr "%s\n\n\n" (Log.rfc_822_date ()) ;


  pr "= Environnement =\n\n" ;
  pr "== System ==\n\n" ;
  print_cmd "uname -a";
  print_cmd "cat /proc/sys/dev/rtc/max-user-freq";
  print_cmd "cat /proc/driver/rtc";
  print_cmd "cat /proc/interrupts";
  print_cmd "cat /proc/asound/version" ;
  print_cmd "cat /proc/asound/timers" ;
  print_cmd "cat /proc/asound/modules" ;
  print_cmd "cat /proc/asound/devices" ;
  print_cmd "cat /proc/asound/seq/drivers" ;
  print_cmd "cat /proc/asound/seq/clients" ;
  print_cmd "ls -l /dev/rtc /dev/snd/seq /dev/snd/timer";
  print_cmd "groups";

  pr "== Ocaml Data ==\n\n" ;
  pr  "| Sys.max_array_length    | %d |\n" Sys.max_array_length ;
  pr  "| Sys.max_string_length   | %d |\n" Sys.max_string_length;
  pr  "| Sys.ocaml_version       | %s |\n" Sys.ocaml_version;
  pr  "| Sys.os_type             | %s |\n" Sys.os_type;
  pr  "| Sys.word_size           | %d |\n" Sys.word_size;

  pr "\n== Libraries ==\n\n" ;
  let x,y,z = GMain.Main.version in
  pr "- GTK version: ``%d.%d.%d``\n\n" x y z ;
  pr  "- GtkInit.locale:\n```\n%s\n```\n" (
    try 
      while true do
        let i = String.index GtkInit.locale ';' in
        GtkInit.locale.[i] <- '\n' ;
      done;
      GtkInit.locale (* never used !*)
    with e -> GtkInit.locale
  );
  pr "- JACK: %s\n" (str_of_cmd "pkg-config --modversion jack");
)


(******************************************************************************)
(** {3 Command line functions} *)

(**/**)
module S = StringServer
(**/**)
let short_usage = 
  "This is " ^ !S.App.app_name ^ " v. " ^  !S.App.version

let gui = ref false
let show_licence = ref false
let show_version = ref false
let g_file_to_open = ref None

let options = Arg.align [
  ("-gui", Arg.Set gui, " Launch GUI");
  ("-parse", Arg.String test_parse_and_print_midi_file,
  "<midi_file> (Test) Parse and print MIDI file");
  ("-inspect", Arg.String make_inspection,
  "<target_file> Process portability inspection and write a report");
  ("-song", Arg.String (fun s -> g_file_to_open := Some s),
  "<xml_file> Open the file");
  ("-jackname", Arg.Set_string S.App.jack_client_name,
  "<name> Sets jack client identifier to <name>");
  ("-licence", Arg.Set show_licence, " Show Licence");
  ("-version", Arg.Set show_version, " Print version (one parsable line)");
]


let ignore_unknown_arguments str = (
  Log.warn "argument '%s' ignored.\n" str;
)


(******************************************************************************)
(** {3 Main} *)

let main () = (
  Arg.parse options ignore_unknown_arguments short_usage;
  if 1 >= !Arg.current then (
    Arg.usage options short_usage;
    exit 1;
  );

  if !show_version then (
    Printf.printf "%s\n%!" !StringServer.App.version;
  );
  if !show_licence then (
    Printf.printf "%s" !StringServer.App.licence;
  );
  if !gui then (
    match !g_file_to_open with
    | None -> Gui.start () ;
    | Some open_file -> Gui.start ~open_file ();
  );
)

let () = Printexc.print main () ;

